/*
 * Created on Sep 29, 2005
 * @author cschaff
 * Copyright Amadeus 2005
 */
package com.amadeus.spin.standard.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.soap.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.amadeus.spin.devtool.soap.shooter.FatalException;

/**
 * Dom4jUtils Created on Sep 29, 2005
 */
public abstract class Dom4jUtils {

  public static final String DEFAULT_ENCODING = Constants.HEADERVAL_CHARSET_UTF8;

  /**
   * Creates a Dom node from an xml string
   * 
   * @param xmlString
   * @return
   * @throws FatalException
   */
  public static Node createDOMnode(String xmlString) throws FatalException {
    return getDocumentFromString(xmlString).getDocumentElement();
  }

  /**
   * Get xml content with proper encoding encoding
   *
   * @param xmlString
   * @param encoding
   * @return
   * @throws TransformerFactoryConfigurationError
   * @throws TransformerException
   * @throws IOException
   */
  public static String getTidyXml(String xmlString, String encoding) throws TransformerFactoryConfigurationError,
      TransformerException {
    StringWriter formattedStuff = new StringWriter();
    if (encoding == null) {
      encoding = DEFAULT_ENCODING;
    }
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
    transformer.transform(new StreamSource(new StringReader(xmlString)), new StreamResult(formattedStuff));
    return formattedStuff.toString();
  }

  /**
   * Creates a document from a file path
   *
   * @param filePath
   * @return
   * @throws IOException
   * @throws SAXException
   * @throws ParserConfigurationException
   */
  public static Document getDocumentFromFile(String filePath)
      throws IOException, SAXException, ParserConfigurationException {
    DocumentBuilder db = createDocBuilder();
    return db.parse(new File(filePath));
  }

  /**
   * transforms an xml string to a standard document
   *
   * @param xml
   * @return
   * @throws FatalException
   * @throws IOException
   * @throws SAXException
   * @throws ParserConfigurationException
   */
  public static Document getDocumentFromString(String xml) throws FatalException {
    try {
      DocumentBuilder db = createDocBuilder();
      String enc = EncodingUtils.getStringEncoding(xml);
      if (enc == null) {
        enc = DEFAULT_ENCODING;
      }
      return db.parse(new ByteArrayInputStream(xml.getBytes(enc)));
    }
    catch (org.xml.sax.SAXException se) {
      throw new FatalException(se.getMessage(), se);
    }
    catch (IOException e) {
      throw new FatalException(e.getMessage(), e);
    }
    catch (ParserConfigurationException e) {
      throw new FatalException(e.getMessage(), e);
    }
  }

  /**
   * transforms a w3c document to a string
   * 
   * @param doc
   * @return
   * @throws FatalException
   */
  public static String getStringFromDocument(Document doc) throws FatalException {
    try {

      DOMSource domSource = new DOMSource(doc);
      StringWriter writer = new StringWriter();
      StreamResult result = new StreamResult(writer);
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer transformer = tf.newTransformer();

      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
      transformer.setOutputProperty(OutputKeys.METHOD, "xml");
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");

      transformer.transform(domSource, result);
      return writer.toString();
    }
    catch (TransformerConfigurationException e) {
      throw new FatalException(e.getMessage(), e);
    }
    catch (TransformerException e) {
      throw new FatalException(e.getMessage(), e);
    }
  }

  /**
   * Same as getDocumentFromFile(String filePath) with input source
   *
   * @param is
   * @return
   * @throws IOException
   * @throws SAXException
   * @throws ParserConfigurationException
   */
  public static Document getDocumentFromFile(InputSource is)
      throws IOException, SAXException, ParserConfigurationException {
    DocumentBuilder db = createDocBuilder();
    return db.parse(is);
  }

  /**
   *
   * @return
   * @throws ParserConfigurationException
   */
  private static DocumentBuilder createDocBuilder() throws ParserConfigurationException {
    DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
    // Specify a parser supporting namespaces.
    fact.setNamespaceAware(true);
    // Specify a validating parser.
    fact.setValidating(false);
    return fact.newDocumentBuilder();
  }

}
